'use strict'

const { dialog, shell, app, nativeImage } = require('electron')
const https = require('https')
const path = require('path')
const log4js = require('log4js')
const fs = require('fs')
const AppConfig = require('../../configuration')

const versionRegex = /^v[0-9]+\.[0-9]+\.*[0-9]*$/

let Common = (AppConfig.readSettings('language') === 'zh_CN') ? require('../../common_cn') : require('../../common')

class UpdateHandler {
  constructor() {
    this.logger = log4js.getLogger("UpdateHandler")
    this.logger.level = AppConfig.readSettings("logger-level")
  }

  checkForUpdate(version, silent) {
    this.logger.debug("check update")
    https.get({
        host: Common.GITEE_HOST,
        headers: { 'User-Agent': Common.USER_AGENT, 'Accept': 'application/json' },
        path: Common.GITEE_RELEASE_LATEST_PATH,
    }, (response) => {
      let raw = ''
      response.on('data', (chunk) => { raw += chunk })
      response.once('end', () => {
        let latest = null
        let latest_version = null
        try {
          latest = JSON.parse(raw)
          latest_version = JSON.parse(latest.release.tag.message).version
        } catch(err) {
          this.logger.error(err)
        }
        if(!latest_version || !versionRegex.test(latest_version)) {
          this.logger.trace("update no found, no latest release")
          return
        } else {
          this.logger.debug(latest_version)
          if (latest_version > version) {
            this.doUpdate(latest_version, silent)
          } else if(latest_version === version) {
            dialog.showMessageBox({ title: Common.UPDATE_NA_TITLE, message: Common.UPDATE_ERROR_LATEST(version), }).then()
          } else {
            dialog.showMessageBox({ title: Common.UPDATE_NA_TITLE, message: Common.UPDATE_NA_TITLE, }).then()
          }
        }
      })
    })
  }

  doUpdate(version, silent) {
    const promise = new Promise((res, rej) => {
      if (Common.ELECTRON === app.getName()) {
        rej(Common.UPDATE_ERROR_ELECTRON)
      }
      const req = https.get({
        host: Common.GITEE_HOST,
        headers: { 'User-Agent': Common.USER_AGENT, 'Accept': 'application/json' },
        path: `${Common.GITEE_RELEASES}/${version}`,
      }, (response) => {
        let body = ''
        response.on('data', (d) => { body += d })
        response.once('end', () => { this._parseUpdateData(body, res, rej) })
      })
      req.on('error', (err) => {
        this.logger.debug("request err:", err.message)
        rej(Common.UPDATE_ERROR_NETWORK)
      })
      req.end()
    }).then((fetched) => {
      this.showDialog(fetched.name, fetched.description, 'Update', (promise) => {
        if (promise.response === 0) return
        shell.openExternal(`https://${Common.GITEE_HOST}${fetched.url}`)
      })
    }).catch((message) => {
      this.logger.debug(message)
      if (silent) { return }
      if (!message) { message = Common.UPDATE_ERROR_UNKNOWN }
      this.showDialog(Common.UPDATE_NA_TITLE, message, 'OK')
    })
  }

  showDialog(head, msg, positiveButton, callback) {
    const iconImage = nativeImage.createFromPath(path.join(__dirname, '../../renderer/ui/icon.png'))
    dialog.showMessageBox({
      type: 'info',
      buttons: ['Cancel', positiveButton],
      defaultId: 1,
      cancelId: 0,
      title: head,
      message: msg,
      icon: iconImage,
    }).then(callback)
  }

  _parseUpdateData(body, res, rej) {
    let data = null
    try {
      data = JSON.parse(body)
    } catch(error) {
      this.logger.fatal("response json parse error")
      data = null
    }
    if (!data || typeof(data.release) === 'undefined') {
      rej(Common.UPDATE_ERROR_EMPTY_RESPONSE)
    } else {
      let fetched = {
        version: data.release.tag.name,
        is_prerelease: data.release.release.is_prerelease,
        name: data.release.release.title,
        description: data.release.release.description
      }

      data.release.release.attach_files.forEach((L) => {
        if(process.platform === 'win32') {
          if(L.name.endsWith('.exe')) {
            fetched.url = L.download_url
          }
        } else if(process.platform === 'darwin') {
          if(L.name.endsWith('.zip')) {
            fetched.url = L.download_url
          }
        } else if(process.platform === 'linux') {
          let os_release = fs.readFileSync('/etc/os-release', 'ascii').split('\n')
          let id_like = null
          os_release.forEach((line) => {
            if(line.startsWith('ID_LIKE')) {
              if(/^.*debian$/.test(line)) {
                if(L.name.endsWith('.deb')) {
                  fetched.url = L.download_url
                }
              } else {
                if(L.name.endsWith('.rpm')) {
                  fetched.url = L.download_url
                }
              }
            }
          })
        }
      })
      this.logger.trace(fetched)
      if(typeof(fetched.url) === "undefined") {
        rej(Common.UPDATE_ERROR_EMPTY_RESPONSE)
      } else {
        res(fetched)
      }
    }
  }
}

module.exports = UpdateHandler
